package dashboard.json;

import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentLinkedQueue;

import net.sf.json.JSONObject;

import org.apache.commons.lang.StringUtils;
import org.codehaus.jackson.map.DeserializationConfig;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.ser.StdSerializerProvider;
import org.codehaus.jackson.map.ser.impl.SimpleBeanPropertyFilter;
import org.codehaus.jackson.map.ser.impl.SimpleFilterProvider;
import org.codehaus.jackson.map.ser.std.NullSerializer;
import org.codehaus.jackson.type.TypeReference;
public class JsonJacksonUtils {
	    private static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
	    static boolean isPretty = false;
	    private static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
	    static StdSerializerProvider sp = new StdSerializerProvider();
	    static {
	        sp.setNullValueSerializer(NullSerializer.instance);
	    }
	  
	    static SimpleDateFormat defaultDateFormat = new SimpleDateFormat(DEFAULT_DATE_FORMAT);
	     
	    public static ConcurrentLinkedQueue<ObjectMapper> mapperQueue = new ConcurrentLinkedQueue<ObjectMapper>();
	     
	    public static ObjectMapper getObjectMapper() {
	        ObjectMapper mapper = mapperQueue.poll();
	        if(mapper == null) {
	            mapper = new  ObjectMapper(null, sp, null);
	        }
	        return mapper;
	    }
	     
	    public static void returnMapper(ObjectMapper mapper) {
	        if(mapper != null) {
	            mapperQueue.offer(mapper);
	        }
	    }
	     
	    private static People p;
	    
	    private static int num = 10;
	 
	    static People createAPeople(String name, List<People> friends) {
	        People newPeople = new People();
	        newPeople.setName(name);
	        newPeople.setFullName(new FullName(name+"_first", name+"_middle", name+"_last"));
	        newPeople.setAge(24);
	        List<String> hobbies = new ArrayList<String>();
	        hobbies.add("篮球");
	        hobbies.add("游泳");
	        hobbies.add("coding");
	        newPeople.setHobbies(hobbies);
	        Map<String, String> clothes = new HashMap<String, String>();
	        clothes.put("coat", "Nike");
	        clothes.put("trousers", "adidas");
	        clothes.put("shoes", "安踏");
	        newPeople.setClothes(clothes);
	        newPeople.setFriends(friends);
	        newPeople.setBirthday(new Date());
	        return newPeople;
	    }
	    
	    public static boolean isPretty() {
	        return isPretty;
	    }
	 
	    public static void setPretty(boolean isPretty) {
	        JsonJacksonUtils.isPretty = isPretty;
	    }
	 
	    /**
	     * JSON串转换为Java泛型对象，可以是各种类型，此方法最为强大。用法看测试用例。
	     * 
	     * @param <T>
	     * @param jsonString
	     *            JSON字符串
	     * @param tr
	     *            TypeReference,例如: new TypeReference< List<FamousUser> >(){}
	     * @return List对象列表
	     */
	    @SuppressWarnings("unchecked")
	    public static <T> T json2GenericObject(String jsonString,TypeReference<T> tr, String dateFormat) {
	        if (StringUtils.isNotEmpty(jsonString)) {
	            ObjectMapper mapper = getObjectMapper(); 
	            try {
//	              ObjectMapper objectMapper = new ObjectMapper(null, sp, null);
	                mapper.disable(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES); 
	 
	                if (StringUtils.isBlank(dateFormat)) {
	                    mapper.setDateFormat(defaultDateFormat);
	                } else {
	                    SimpleDateFormat sdf = (SimpleDateFormat) defaultDateFormat.clone();
	                    sdf.applyPattern(dateFormat);
	                    mapper.setDateFormat(sdf);
	               }
	                return (T) mapper.readValue(jsonString, tr);
	            } catch (Exception e) {
	               e.printStackTrace();
	            } finally {
	                returnMapper(mapper);
	            }
	        }
	        return null;
	    }
	     
	    /**
	     * Json字符串转Java对象
	     * 
	     * @param jsonString
	     * @param c
	     * @return
	     */
	    public static <T> T json2Object(String jsonString, Class<T> c,String dateFormat) {
	        if (StringUtils.isNotEmpty(jsonString)) {
	            ObjectMapper mapper = getObjectMapper(); 
	            try {
	                 
//	              ObjectMapper objectMapper = new ObjectMapper(null, sp, null);
//	                mapper.disable(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES); 
//	                if (StringUtils.isBlank(dateFormat)) {
//	                    mapper.setDateFormat(defaultDateFormat);
//	                } else {
//	                    SimpleDateFormat sdf = (SimpleDateFormat) defaultDateFormat.clone();
//	                    sdf.applyPattern(dateFormat);
//	                    mapper.setDateFormat(sdf);
//	                }
	                return (T)mapper.readValue(jsonString, c);
	            } catch (Exception e) {
	                e.printStackTrace();
	            } finally {
	                returnMapper(mapper);
	            }
	        }
	        return null;
	    }
	     
	 
	    /**
	     * Java对象转Json字符串
	     * 
	     * @param object
	     *            目标对象
	     * @param executeFields
	     *            排除字段
	     * @param includeFields
	     *            包含字段
	     * @param dateFormat
	     *            时间格式化
	     * @param isPretty
	     *            是否格式化打印 default false
	     * @return
	     */
	    public static String toJson(Object object, String[] executeFields,
	            String[] includeFields, String dateFormat) {
	        String jsonString = "";
	        ObjectMapper mapper = getObjectMapper(); 
	        try {
//	            BidBeanSerializerFactory bidBeanFactory = BidBeanSerializerFactory.instance;
	            if (StringUtils.isBlank(dateFormat)) {
	                mapper.setDateFormat(defaultDateFormat);
	            } else {
	                SimpleDateFormat sdf = (SimpleDateFormat) defaultDateFormat.clone();
	                sdf.applyPattern(dateFormat);
	                mapper.setDateFormat(sdf);
	            }
	            if (includeFields != null) {
	                String filterId = "includeFilter";
	                mapper.setFilters(new SimpleFilterProvider().addFilter(
	                        filterId, SimpleBeanPropertyFilter
	                                .filterOutAllExcept(includeFields)));
//	                bidBeanFactory.setFilterId(filterId);
//	                mapper.setSerializerFactory(bidBeanFactory);
	 
	            } else if (includeFields == null && executeFields != null) {
	                String filterId = "executeFilter";
	                mapper.setFilters(new SimpleFilterProvider().addFilter(
	                        filterId, SimpleBeanPropertyFilter
	                                .serializeAllExcept(executeFields)));
//	                bidBeanFactory.setFilterId(filterId);
//	                mapper.setSerializerFactory(bidBeanFactory);
	            }
	           if (isPretty) {
	                jsonString = mapper.writerWithDefaultPrettyPrinter()
	                        .writeValueAsString(object);
	            } else {
	                jsonString = mapper.writeValueAsString(object);
	            }
	        } catch (Exception e) {
	            e.printStackTrace();
	        } finally {
	            returnMapper(mapper);
	        }
	        return jsonString;
	    } 


	 public static void jsonSer(){
		List<People> friends = new ArrayList<People>();
		friends.add(createAPeople("小明", null));
		friends.add(createAPeople("Tony", null));
		friends.add(createAPeople("陈小二", null));
		p = createAPeople("邵同学", friends);

		long startTime,endTime,dif;
		int num = 500000;  
		startTime = System.currentTimeMillis();
		String jsonString = null;
		/*  codehaus.jackson */
		for (int i = 0; i < num; i++) {
//			String jsonString = GsonUtils.bean2Json(p);
			jsonString = toJson(p, null, null, "yyyy-MM-dd");
//			String jsonString = JsonUtils.toJson(p);
//			String jsonString = DJsonUtils.bean2Json(p);
//			String jsonString = FastJsonUtils.bean2Json(p,"yyyy-MM-dd");
//			System.out.println(jsonString);
		}
		endTime = System.currentTimeMillis();
		dif = endTime - startTime;
		System.err.println("codehaus.jackson 序列化:" + num + " 笔数据  cost :" + dif + " 毫秒  平均:" + (Double.valueOf(num) / Double.valueOf(Double.valueOf(dif) / 1000) + " 笔/秒"));
	
		/*  JsonUtils jackson*/
		startTime = System.currentTimeMillis();
		for (int i = 0; i < num; i++) {
			jsonString = JsonUtils.toJson(p);
		}
		endTime = System.currentTimeMillis();
		dif = endTime - startTime;
		System.err.println("JsonUtils序列化:" + num + " 笔数据  cost :" + dif + " 毫秒  平均:" + (Double.valueOf(num) / Double.valueOf(Double.valueOf(dif) / 1000) + " 笔/秒"));

		
		/*  fastJson */
		startTime = System.currentTimeMillis();
		for (int i = 0; i < num; i++) {
			jsonString = FastJsonUtils.bean2Json(p);
		}
		endTime = System.currentTimeMillis();
		dif = endTime - startTime;
		System.err.println("fastJson序列化:" + num + " 笔数据  cost :" + dif + " 毫秒  平均:" + (Double.valueOf(num) / Double.valueOf(Double.valueOf(dif) / 1000) + " 笔/秒"));
		
		/*  fastJson 格式化日期  */
		startTime = System.currentTimeMillis();
		for (int i = 0; i < num; i++) {
			jsonString = FastJsonUtils.bean2Json(p,"yyyy-MM-dd");
		}
		endTime = System.currentTimeMillis();
		dif = endTime - startTime;
		System.err.println("fastJson 格式化日期序列化:" + num + " 笔数据  cost :" + dif + " 毫秒  平均:" + (Double.valueOf(num) / Double.valueOf(Double.valueOf(dif) / 1000) + " 笔/秒"));
		
		/*   Gson  */
		startTime = System.currentTimeMillis();
		for (int i = 0; i < num; i++) {
			jsonString = GsonUtils.bean2Json(p);
		}
		endTime = System.currentTimeMillis();
		dif = endTime - startTime;
		System.err.println(" Gson 序列化:" + num + " 笔数据  cost :" + dif + " 毫秒  平均:" + (Double.valueOf(num) / Double.valueOf(Double.valueOf(dif) / 1000) + " 笔/秒"));
		
		/*
		 * 数据量少于10万的情况下，测试： Gson > fastJson >= jackson
		 * 数据量较大的情况下，测试： jackson > fastJson > Gson
		 * 数据量不是很大的情况下Gson是个不错的选择。
		 * 随着数据量增大jackson性能显著提升，fastJson平稳，Gson下降。
		 * 
		 */
	 }

	 public static void jsonDesc(){
			List<People> friends = new ArrayList<People>();
			friends.add(createAPeople("小明", null));
			friends.add(createAPeople("Tony", null));
			friends.add(createAPeople("陈小二", null));
			p = createAPeople("邵同学", friends);
	 
	        String jsonStr = toJson(p, null, null, "yyyy-MM-dd");
	        
	        System.out.println(jsonStr);
//	        GsonUtils.json2Bean(jsonStr, People.class);
//	        json2Object(jsonStr, People.class, "yyyy-MM-dd");
//	        Map<String, Object> map = json2Object(jsonStr, Map.class, "yyyy-MM-dd");
//	        JacksonUtils.json2Bean(jsonStr, People.class);
//	        FastJsonUtils.json2Bean(jsonStr, People.class);
	 
	    	long startTime,endTime,dif;
			int num = 2000000;  
			startTime = System.currentTimeMillis();
			/*  codehaus.jackson */
			for (int i = 0; i < num; i++) {
				json2Object(jsonStr, People.class, "yyyy-MM-dd");
			}
			endTime = System.currentTimeMillis();
			dif = endTime - startTime;
			System.err.println("codehaus.jackson 反序列化:" + num + " 笔数据  cost :" + dif + " 毫秒  平均:" + (Double.valueOf(num) / Double.valueOf(Double.valueOf(dif) / 1000) + " 笔/秒"));
		
			/*  JsonUtils jackson*/
			startTime = System.currentTimeMillis();
			for (int i = 0; i < num; i++) {
				JsonUtils.fromJSON(jsonStr,  People.class);
			}
			endTime = System.currentTimeMillis();
			dif = endTime - startTime;
			System.err.println("JsonUtils 反序列化:" + num + " 笔数据  cost :" + dif + " 毫秒  平均:" + (Double.valueOf(num) / Double.valueOf(Double.valueOf(dif) / 1000) + " 笔/秒"));

			
			/*  fastJson */
			startTime = System.currentTimeMillis();
			for (int i = 0; i < num; i++) {
				FastJsonUtils.json2Bean(jsonStr, People.class);
			}
			endTime = System.currentTimeMillis();
			dif = endTime - startTime;
			System.err.println("fastJson 反序列化:" + num + " 笔数据  cost :" + dif + " 毫秒  平均:" + (Double.valueOf(num) / Double.valueOf(Double.valueOf(dif) / 1000) + " 笔/秒"));

			/*   Gson  */
			startTime = System.currentTimeMillis();
			for (int i = 0; i < num; i++) {
				GsonUtils.json2Bean(jsonStr, People.class);
			}
			endTime = System.currentTimeMillis();
			dif = endTime - startTime;
			System.err.println(" Gson 反序列化:" + num + " 笔数据  cost :" + dif + " 毫秒  平均:" + (Double.valueOf(num) / Double.valueOf(Double.valueOf(dif) / 1000) + " 笔/秒"));
  
	 }
	 
	    /**
	 * @param args
	 */
	public static void main(String[] args) {
//		jsonSer();
//		jsonDesc();
		String jsonString = "{'new_uv':'1','new_session':'1','init_refer':'http%3a%2f%2fwww.haosou.com%2fs%3fie%3dutf-8%26shb%3d1%26src%3dhome_haosou.com%26q%3d%25e5%25a5%25bd%25e5%25a3%25b0%25e9%259f%25b3','br58':'','coords':'_','tag_tmp':'','spm':'','utm_campaign':'','utm_source':'','infoid':'23047007373577','gtid':'14446402439550.45236907802951553','cate':'1,12','actiontype':'m_zhuzhan','area':'10367,10373','pagetype':'detail','page':'xiaomi','actiontype':'xiaomi','source':'0','userid':'32684707685643','is_biz':'false','ga_pageview':'/m/baoting/house/ershoufang/detail/'}";
		
//		System.err.println(GsonUtils.json2Bean(jsonString, Map.class));
		System.err.println(JsonUtils.fromJSON(jsonString, Map.class));
		Map<String, String> map = JsonUtils.fromJSON(jsonString,new TypeReference<Map<String, String>>() {});
		System.err.println(map);
	}

}
